package net.p2pcdn.common;

import org.apache.commons.lang3.time.DateUtils;
import org.apache.commons.lang3.time.FastDateFormat;
import org.springframework.core.convert.converter.Converter;
import org.springframework.util.Assert;

import java.time.Duration;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.List;

/**
 * 创建人：zx
 * 修改人：zx
 *
 * @version 1.0.0
 */
public class Date2StringConverter implements Converter<Date, String> {
    private static final FastDateFormat _yyyyMMdd = FastDateFormat.getInstance("yyyy-MM-dd");
    private static final FastDateFormat _yyyyMMddHHmmSS = FastDateFormat.getInstance("yyyy-MM-dd HH:mm:ss");
    private static final FastDateFormat _yyyyMMddHHmm = FastDateFormat.getInstance("yyyy-MM-dd HH:mm");
    private static final FastDateFormat _hhmm = FastDateFormat.getInstance("HH:mm");
    private static final FastDateFormat _yyyyMM = FastDateFormat.getInstance("yyyy-MM");
    private final static FastDateFormat _yyyyMMddHHmmss = FastDateFormat.getInstance("yyyyMMddHHmmss");
    private static final FastDateFormat _yy = FastDateFormat.getInstance("yy");
    private static final FastDateFormat _mmddHHmm = FastDateFormat.getInstance("yyyy年MM月dd日 HH:mm");

    @Override
    public String convert(Date source) {
        if (source == null) {
            return null;
        }
        return _yyyyMMdd.format(source);
    }

    /**
     * @param date
     * @return yyyy-MM-dd
     */
    public static String yyyyMMdd(Date date) {
        Assert.notNull(date, "日期不能为空");
        return _yyyyMMdd.format(date);
    }

    public static String yy(Date date) {
        Assert.notNull(date, "日期不能为空");
        return _yy.format(date);
    }

    /**
     * @param timeInMillseconds
     * @return yyyy-MM-dd
     */
    public static String yyyyMMdd(long timeInMillseconds) {
        return _yyyyMMdd.format(timeInMillseconds);
    }

    /**
     * @param date
     * @return yyyy-MM-dd
     */
    public static String yyyyMMdd(Calendar date) {
        return _yyyyMMdd.format(date);
    }

    /**
     * @param date
     * @return yyyy-MM-dd HH:mm:ss
     */
    public static String format(Date date) {
        return _yyyyMMddHHmmSS.format(date);
    }

    /**
     * @param timeInMillseconds
     * @return yyyy-MM-dd HH:mm:ss
     */
    public static String format(long timeInMillseconds) {
        return _yyyyMMddHHmmSS.format(timeInMillseconds);
    }

    /**
     * @param date
     * @return yyyy-MM-dd HH:mm:ss
     */
    public static String format(Calendar date) {
        return _yyyyMMddHHmmSS.format(date);
    }

    /**
     * @param timeInMillseconds
     * @return yyyy-MM-dd HH:mm
     */
    public static String yyyyMMddHHmm(long timeInMillseconds) {
        return _yyyyMMddHHmm.format(timeInMillseconds);
    }

    /**
     * @param date
     * @return yyyy-MM-dd HH:mm
     */
    public static String yyyyMMddHHmm(Date date) {
        return _yyyyMMddHHmm.format(date);
    }

    /**
     * @param calendar
     * @return yyyy-MM-dd HH:mm
     */
    public static String yyyyMMddHHmm(Calendar calendar) {
        return _yyyyMMddHHmm.format(calendar);
    }

    /**
     * @param date
     * @return hh:mm
     */
    public static String hhmm(long date) {
        return _hhmm.format(date);
    }


    /**
     * @param date
     * @return hh:mm
     */
    public static String hhmm(Calendar date) {
        return _hhmm.format(date);
    }

    /**
     * @param date
     * @return hh:mm
     */
    public static String hhmm(Date date) {
        return _hhmm.format(date);
    }


    /**
     * @param date
     * @return yyyy-MM
     */
    public static String yyyyMM(long date) {
        return _yyyyMM.format(date);
    }


    /**
     * @param date
     * @return yyyy-MM
     */
    public static String yyyyMM(Calendar date) {
        return _yyyyMM.format(date);
    }

    /**
     * @param date
     * @return yyyy-MM
     */
    public static String yyyyMM(Date date) {
        return _yyyyMM.format(date);
    }


    /**
     * @param date
     * @return yyyyMMddHHmmss
     */
    public static String yyyyMMddHHmmss(long date) {
        return _yyyyMMddHHmmss.format(date);
    }

    /**
     * @param date
     * @return yyyyMMddHHmmss
     */
    public static String yyyyMMddHHmmss(Calendar date) {
        return _yyyyMMddHHmmss.format(date);
    }

    /**
     * @param date
     * @return yyyyMMddHHmmss
     */
    public static String yyyyMMddHHmmss(Date date) {
        return _yyyyMMddHHmmss.format(date);
    }

    public static List<String> splitDateInterval(Date from, Date to) {
        return splitDateInterval(from, to, false);
    }

    public static List<String> splitDateInterval(Date from, Date to, boolean simply) {
        if (from.compareTo(to) > 0) {
            throw new IllegalArgumentException("开始时间不能大于截止时间");
        }
        String startTime = yyyyMMdd(from);
        String endTime = yyyyMMdd(to);
        List<String> list = new ArrayList<>();
        if (startTime.equals(endTime)) {
            list.add(startTime);
            return list;
        }
        while (startTime.compareTo(endTime) <= 0) {
            list.add(startTime);
            from = DateUtils.addDays(from, 1);
            startTime = yyyyMMdd(from);
        }
        List<String> finalList = new ArrayList<>();
        if (simply) {
            list.forEach(item -> finalList.add(item.replace("-", "")));
            list = finalList;
        }
        return list;
    }

    public static Date getCurrentWeekDayStartTime() {
        Calendar from = Calendar.getInstance();
        from.setFirstDayOfWeek(Calendar.MONDAY);
        from.set(Calendar.DAY_OF_WEEK, Calendar.MONDAY);
        return DateUtils.truncate(from.getTime(),Calendar.DATE);
    }


    public static Date getCurrentWeekDayEndTime() {
        Date date = getCurrentWeekDayStartTime();
        date = DateUtils.addWeeks(date,1);
        date = DateUtils.truncate(date, Calendar.DATE);
        date = DateUtils.addMilliseconds(date, -1);
        return date;
    }


    public static Date getDateOfStartTime() {
        Calendar c = Calendar.getInstance();
        return DateUtils.truncate(c.getTime(), Calendar.DATE);
    }

    public static Date getDateOfEndTime() {
        Calendar c = Calendar.getInstance();
        c.add(Calendar.DATE, 1);
        Date date = DateUtils.truncate(c.getTime(), Calendar.DATE);
        return DateUtils.addSeconds(date, -1);
    }

    public static Date getCurrentMonthStartTime() {
        Calendar c = Calendar.getInstance();
        return DateUtils.truncate(c.getTime(), Calendar.MONTH);
    }

    public static Date getCurrentMonthEndTime() {
        Date date = getCurrentMonthStartTime();
        date = DateUtils.addMonths(date, 1);
        date = DateUtils.addMilliseconds(date, -1);
        return date;
    }


    public static Date getCurrentYearStartTime() {
        Calendar c = Calendar.getInstance();
        return DateUtils.truncate(c.getTime(), Calendar.YEAR);
    }

    public static Date getCurrentYearEndTime() {
        Date date = getCurrentYearStartTime();
        date = DateUtils.addYears(date, 1);
        date = DateUtils.addMilliseconds(date, -1);
        return date;
    }

    public static String MMddHHmm(Date date) {
        return _mmddHHmm.format(date);
    }

    public static long getDuration(Date from, Date to) {
        LocalDateTime st = from.toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime();
        LocalDateTime et = to.toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime();
        Duration period = Duration.between(st, et);
        return period.toDays();
    }

    public static List<String> splitMonthInterval(Date start, Date end) {
        FastDateFormat yyyyMM = FastDateFormat.getInstance("yyyyMM");
        Calendar from = Calendar.getInstance();
        from.setTime(start);
        Calendar to = Calendar.getInstance();
        to.setTime(end);

        int fromYear = from.get(Calendar.YEAR);
        int fromMonth = from.get(Calendar.MONTH);
        int toYear = to.get(Calendar.YEAR);
        int toMonth = to.get(Calendar.MONTH);
        toMonth += (toYear - fromYear) * 12;
        List<String> monthLabels = new ArrayList<>();
        monthLabels.add(yyyyMM.format(from));
        do {
            fromMonth++;
            from.add(Calendar.MONTH, 1);
            monthLabels.add(yyyyMM.format(from));
        } while (fromMonth < toMonth);
        return monthLabels;
    }

    public static List<String> splitWeekInterval(Date start, Date end) {
        FastDateFormat _yyyyWW = FastDateFormat.getInstance("yyyyww");
        Calendar from = Calendar.getInstance();
        from.setTime(start);
        Calendar to = Calendar.getInstance();
        to.setTime(end);
        int fromWeek = from.get(Calendar.WEEK_OF_YEAR);
        int toWeek = to.get(Calendar.WEEK_OF_YEAR);
        List<String> weekLabels = new ArrayList<>();
        weekLabels.add(_yyyyWW.format(from));
        do {
            fromWeek++;
            from.add(Calendar.WEEK_OF_YEAR, 1);
            weekLabels.add(_yyyyWW.format(from));
        } while (fromWeek < toWeek);
        weekLabels.forEach(System.out::println);
        return weekLabels;
    }

    public static void main(String[] args) {
        System.out.println(getCurrentWeekDayStartTime());
        System.out.println(getCurrentWeekDayEndTime());
    }
}
